package worker

import (
	"sieve_engine/lib/app"
	"sieve_engine/lib/config"
	"time"
)

var (
	fMaxWorker = *config.Int("lib.worker.workers.max", 64, "")
	fNum       = *config.Int("lib.worker.workers.num", 2, "")
)

type Workers[T any] struct {
	num     int
	exist   []bool
	ch      chan T
	handler func(T)
}

func NewWorkers[T any](handler func(T)) *Workers[T] {
	if fMaxWorker < 1 {
		fMaxWorker = 1
	}
	w := &Workers[T]{
		exist:   make([]bool, fMaxWorker),
		ch:      make(chan T),
		handler: handler,
	}
	w.SetNum(fNum)
	app.Async(func() {
		for {
			for i := 0; i < w.num; i++ {
				if !w.exist[i] {
					w.runWorker(i)
				}
			}
			time.Sleep(time.Second)
		}
	})
	return w
}

func (w *Workers[T]) SetNum(num int) {
	if num < 1 {
		num = 1
	}
	if num > fMaxWorker {
		num = fMaxWorker
	}
	w.num = num
}

func (w *Workers[T]) Handle(msg T) {
	w.ch <- msg
}

func (w *Workers[T]) runWorker(id int) {
	w.exist[id] = true
	app.AsyncSafe(func() {
		defer func() { w.exist[id] = false }()
		for {
			select {
			case <-app.CTX.Done():
				return
			case msg := <-w.ch:
				w.handler(msg)
				if id >= w.num {
					return
				}
			}
		}
	})
}
